/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

part of flutter_native_splash_cli;

/// Image template
class _HarmonyIconTemplate {
  final String directoryName;
  final double pixelDensity;

  _HarmonyIconTemplate({
    required this.directoryName,
    required this.pixelDensity,
  });
}

final _harmonyImagesTemplates = _generateHarmonyImageTemplates();
final _harmonyImageDarkTemplates = _generateHarmonyImageTemplates(dark: true);

List<_HarmonyIconTemplate> _generateHarmonyImageTemplates({
  bool dark = false,
}) {
  return <_HarmonyIconTemplate>[
    _HarmonyIconTemplate(
      directoryName: dark ? 'dark/media' : 'base/media',
      pixelDensity: 4,
    ),
  ];
}

/// Create Harmony splash screen
void _createHarmonySplash({
  required String? imagePath,
  required String? darkImagePath,
  required String? color,
  required String? darkColor,
  required String? backgroundImage,
  required String? darkBackgroundImage,
  required String harmonyModuleJsonFilePath,
  required String harmonyIndexEtsFilePath,
}) {
  _generateHarmonyConfiguration(harmonyModuleJsonFilePath, color, darkColor);

  _applyImageHarmony(imagePath: imagePath);

  _applyImageHarmony(imagePath: darkImagePath, dark: true);

  _createBackground(
    colorString: color,
    darkColorString: darkColor,
    darkBackgroundImageSource: darkBackgroundImage,
    backgroundImageSource: backgroundImage,
    darkBackgroundImageDestination:
        '${_flavorHelper._harmonyResFolder}dark/media/${_flavorHelper.harmonySplashBackgroundImageName}.png',
    backgroundImageDestination:
        '${_flavorHelper._harmonyResFolder}base/media/${_flavorHelper.harmonySplashBackgroundImageName}.png',
  );

  _configSplashPage(harmonyIndexEtsFilePath, color != null);

  print('[Harmony] Updating launch with splash image path...');
}

/// Create splash screen
void _applyImageHarmony({String? imagePath, bool dark = false}) {
  String fileName = '${_flavorHelper._harmonySplashImageName}.png';
  final templates = _getAssociatedHarmonyTemplates(dark: dark);
  if (imagePath == null) {
    for (final template in templates) {
      _deleteImageHarmony(template: template, fileName: fileName);
    }
  } else {
    print(
      '[Harmony] Creating ${dark ? 'dark mode ' : 'default '}'
      '${fileName.split('.')[0]} images',
    );

    final image = decodeImage(File(imagePath).readAsBytesSync());
    if (image == null) {
      print('The file $imagePath could not be read.');
      exit(1);
    }

    _saveImageHarmony(
        templates: templates,
        image: image,
        fileName: fileName,
        harmonyResFolder: _flavorHelper.harmonyResFolder);
  }
}

List<_HarmonyIconTemplate> _getAssociatedHarmonyTemplates({
  required bool dark,
}) {
  return dark ? _harmonyImageDarkTemplates : _harmonyImagesTemplates;
}

/// Saves splash screen image to the project
void _saveImageHarmony({
  required List<_HarmonyIconTemplate> templates,
  required Image image,
  required fileName,
  required String harmonyResFolder,
}) async {
  await Future.wait(
    templates.map(
      (template) => Isolate.run(() async {
        //added file name attribute to make this method generic for splash image.
        final newFile = copyResize(
          image,
          width: image.width * template.pixelDensity ~/ 4,
          height: image.height * template.pixelDensity ~/ 4,
          interpolation: Interpolation.cubic,
        );

        // When the flavor value is not specified we will place all the data inside the main directory.
        final file = File(
          '$harmonyResFolder${template.directoryName}/$fileName',
        );
        await file.create(recursive: true);
        await file.writeAsBytes(encodePng(newFile));
      }),
    ),
  );
}

void _deleteImageHarmony({
  required _HarmonyIconTemplate template,
  required fileName,
}) {
  final file = File(
    '${_flavorHelper.harmonyResFolder}${template.directoryName}/$fileName',
  );
  if (file.existsSync()) {
    print('[Harmony] Deleting $fileName');
    file.deleteSync(recursive: true);
  }
}

void _generateHarmonyConfiguration(
    String jsonPath, String? color, String? darkColor) {
  // Resources path
  var pathList = jsonPath.split('/');
  var needIndex = 4;
  if (pathList.length < needIndex) {
    print('[Harmony] The path of module.json5 is incorrect. Path: $jsonPath.');
    exit(1);
  }
  _flavorHelper._harmonyResFolder =
      '${pathList.sublist(0, needIndex).join('/')}/resources/';

  // Get startWindowIcon from module.json5
  var jsonString = File(jsonPath).readAsStringSync();
  var jsonMap = JSON5.parse(jsonString);
  var module = jsonMap['module'];
  if (module == null) {
    print('[Harmony] Can not find module in $jsonPath.');
    exit(1);
  }
  var abilities = module['abilities'] as List;
  if (abilities.isEmpty) {
    print('[Harmony] Can not find abilities in $jsonPath.');
    exit(1);
  }
  var ability = abilities[0];
  var startWindowIcon = ability['startWindowIcon'] as String?;
  if (startWindowIcon == null) {
    print('[Harmony] Can not find startWindowIcon in $jsonPath.');
    exit(1);
  }
  var startWindowIconPrefix = "\$media:";
  if (!startWindowIcon.startsWith(startWindowIconPrefix)) {
    print('[Harmony] startWindowIcon is not correct. Value: $startWindowIcon.');
    exit(1);
  }
  var iconNameValueList = startWindowIcon.split(startWindowIconPrefix);
  if (iconNameValueList.length != 2) {
    print('[Harmony] startWindowIcon is not correct. Value: $startWindowIcon.');
    exit(1);
  }
  var iconName = iconNameValueList[1];
  _flavorHelper._harmonySplashImageName = iconName;

  /// Update splash background color(s)
  if (color != null && darkColor != null) {
    // Get startWindowBackground from module.json5
    var startWindowBackgroundColor =
        ability['startWindowBackground'] as String?;
    if (startWindowBackgroundColor == null) {
      print('[Harmony] Can not find startWindowBackground in $jsonPath.');
      exit(1);
    }
    var startWindowBackgroundPrefix = "\$color:";
    if (!startWindowBackgroundColor.startsWith(startWindowBackgroundPrefix)) {
      print(
          '[Harmony] startWindowIcon is not correct. Value: $startWindowBackgroundColor.');
      exit(1);
    }
    var colorValueList =
        startWindowBackgroundColor.split(startWindowBackgroundPrefix);
    if (colorValueList.length != 2) {
      print(
          '[Harmony] startWindowBackground is not correct. Value: $startWindowBackgroundColor.');
      exit(1);
    }
    var colorKey = colorValueList[1];
    _updateColorJson(false, colorKey, color);
    _updateColorJson(true, colorKey, darkColor);
  }
}

void _updateColorJson(bool dark, String colorKey, String colorValue) {
  if (!colorValue.startsWith('#')) {
    colorValue = '#$colorValue';
  }

  // Theme path
  var themePath = '${_flavorHelper._harmonyResFolder}${dark ? 'dark' : 'base'}';
  if (!_createFolderIfNeed(themePath)) {
    exit(1);
  }
  // Element path
  var elementPath = '$themePath/element';
  if (!_createFolderIfNeed(elementPath)) {
    exit(1);
  }
  // color.js path
  var jsonPath = '$elementPath/color.json';
  File file = File(jsonPath);
  if (!file.existsSync()) {
    // Create Color.json
    try {
      file.createSync();

      var content = '''
{
  "color": [
    {
      "name": "$colorKey",
      "value": "$colorValue"
    }
  ]
}''';
      file.writeAsStringSync(content);
    } catch (e) {
      print('[Harmony] Create color.json failed at $jsonPath. Error: $e');
      return;
    }
  } else {
    // Update Color.json
    var jsonString = file.readAsStringSync();
    var jsonMap = json.decode(jsonString);
    var color = jsonMap['color'];
    if (color == null) {
      print('[Harmony] Can not find color in $jsonPath.');
      return;
    }
    bool hasColor = false;
    var colorList = color as List;
    for (var obj in colorList) {
      if (obj['name'] == colorKey) {
        obj['value'] = colorValue;
        hasColor = true;
        break;
      }
    }

    if (!hasColor) {
      colorList.add({'name': colorKey, 'value': colorValue});
    }
    const JsonEncoder encoder = JsonEncoder.withIndent('  ');
    final String resultString = encoder.convert(jsonMap);
    file.writeAsString(resultString);

    print('[Harmony] Updating $colorKey at: ${file.path}');
  }
}

bool _createFolderIfNeed(String path) {
  var dir = Directory(path);
  var exist = dir.existsSync();
  if (!exist) {
    try {
      dir.createSync();
    } catch (e) {
      print('[Harmony] Create folder failed. Error: $e');
      return false;
    }
  }
  return true;
}

void _configSplashPage(String indexPagePath, bool isBackgroundColor) {
  File file = File(indexPagePath);
  String content = file.readAsStringSync();

  // Add splashComponentBuilder function
  if (!content.contains('splashComponentBuilder()')) {
    var classStart = 'struct Index {';
    if (!content.contains(classStart)) {
      print('[Harmony] Can not find $classStart in $indexPagePath');
      exit(1);
    }

    var splashComponent = '''
struct Index {
  @Builder
  splashComponentBuilder() {
    Column() {
      Image(\$r("app.media.${_flavorHelper.harmonySplashImageName}")).objectFit(ImageFit.None).backgroundImage(\$r("app.media.${_flavorHelper.harmonySplashBackgroundImageName}"), ${isBackgroundColor ? 'ImageRepeat.XY' : 'ImageRepeat.NoRepeat'})
    }
  }
    ''';
    content = content.replaceFirst(classStart, splashComponent);
  }

  // Update FlutterPage
  if (!content.contains('this.splashComponentBuilder')) {
    var flutterPage = '''FlutterPage({ viewId: this.viewId })''';
    if (!content.contains(flutterPage)) {
      print('[Harmony] Can not find $flutterPage in $indexPagePath');
      exit(1);
    }

    var flutterPageContent = '''
FlutterPage({
        viewId: this.viewId,
        splashScreenView: this.splashComponentBuilder,
      }).backgroundColor(Color.Transparent)''';
    content = content.replaceFirst(flutterPage, flutterPageContent);
  }

  file.writeAsStringSync(content);

  print('[Harmony] Update splash code at: $indexPagePath');
}
